home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Utilities Professional 1-1500
/
Utilities Professional 1-1500 (1994)(WPD)[!].iso
/
12511500
/
var1273.dms
/
var1273.adf
/
AmiCDROM
/
iso9660.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-02
|
18KB
|
763 lines
/* iso9660.c:
*
* Support for the ISO-9660 filing system.
*
* ----------------------------------------------------------------------
* This code is (C) Copyright 1993 by Frank Munkert.
* All rights reserved.
* This software may be freely distributed and redistributed for
* non-commercial purposes, provided this notice is included.
* ----------------------------------------------------------------------
* History:
*
* 02-Dec-93 fmu Bugfix: a logical block of a file extent must not
* necessarily start at a logical sector border.
* 29-Nov-93 fmu - New function Iso_Block_Size().
* - Support for variable logical block sizes.
* 15-Nov-93 fmu Uses_High_Sierra_Protocol added.
* 13-Nov-93 fmu Bad iso_errno return value in Iso_Open_Obj_In_Directory
* corrected.
* 12-Oct-93 fmu Adapted to new VOLUME and CDROM_OBJ structures.
* 24-Sep-93 fmu Two further bugs in Seek_Position fixed.
* 16-Sep-93 fmu Fixed bug in Seek_Position.
* 16-Sep-93 fmu Bugfix: Top level object recognition in CDROM_Info
* had to be changed for Rock Ridge disks.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#ifdef AZTEC_C
#include <pragmas/exec_lib.h>
#include <pragmas/utility_lib.h>
#endif
#ifdef LATTICE
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#endif
#if defined(_DCC) && defined(REGISTERED)
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
extern struct Library *SysBase;
#endif
#include "cdrom.h"
#include "iso9660.h"
#include "rock.h"
extern struct Library *UtilityBase;
t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *);
int iso_errno;
#define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
#define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
/* Check whether the given volume uses the ISO 9660 Protocol.
* The protocol is identified by the sequence
* 'C' 'D' '0' '0' '1'
* in the 2nd..6th byte of sector 16.
*
* Returns TRUE iff the ISO protocol is used; FALSE otherwise.
*/
t_bool Uses_Iso_Protocol (CDROM *p_cdrom)
{
if (!Read_Sector (p_cdrom, 16))
return FALSE;
return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
}
/* Check whether the given volume uses the High Sierra Protocol.
* The protocol is identified by the sequence
* 'C' 'D' 'R' 'O' 'M'
* in the 10th..14th byte of sector 16.
*
* Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
*/
t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
{
if (!Read_Sector (p_cdrom, 16))
return FALSE;
return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
}
t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip)
{
long loc = 16;
extern t_handler g_iso_handler, g_rr_handler;
if (p_volume->protocol == PRO_ISO)
p_volume->handler = &g_iso_handler;
else
p_volume->handler = &g_rr_handler;
p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC);
if (!p_volume->vol_info) {
iso_errno = ISOERR_NO_MEMORY;
return FALSE;
}
for (;;) {
if (!Read_Sector (p_volume->cd, loc)) {
iso_errno = ISOERR_SCSI_ERROR;
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
return FALSE;
}
if (p_volume->cd->buffer[0] == 1) {
memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
break;
}
if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
iso_errno = ISOERR_NO_PVD;
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
return FALSE;
}
loc++;
}
VOL(p_volume,skip) = p_skip;
switch (VOL(p_volume,pvd).block_size_m) {
case 512:
VOL(p_volume,blockshift) = 2;
break;
case 1024:
VOL(p_volume,blockshift) = 1;
break;
case 2048:
default:
VOL(p_volume,blockshift) = 0;
break;
}
return TRUE;
}
void Iso_Close_Vol_Info (VOLUME *p_volume)
{
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
}
CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
{
CDROM_OBJ *obj;
obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
if (!obj) {
iso_errno = ISOERR_NO_MEMORY;
return NULL;
}
obj->obj_info = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
if (!obj->obj_info) {
FreeMem (obj, sizeof (CDROM_OBJ));
return NULL;
}
OBJ(obj,dir) = AllocMem (p_length_of_dir_record, MEMF_PUBLIC);
if (!OBJ(obj,dir)) {
iso_errno = ISOERR_NO_MEMORY;
FreeMem (obj->obj_info, sizeof (t_iso_obj_info));
FreeMem (obj, sizeof (CDROM_OBJ));
return NULL;
}
return obj;
}
/* Get the "CDROM object" for the root directory of the volume.
*/
CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
{
CDROM_OBJ *obj;
obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
if (!obj)
return NULL;
obj->directory_f = TRUE;
obj->volume = p_volume;
obj->pos = 0;
memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
return obj;
}
/* Test on equality of directory names (ignoring case).
*/
int Directory_Names_Equal (char *p_iso_name, int p_length, char *p_name)
{
return Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
p_name[p_length] == 0;
}
/* Compare the name of the directory entry p_iso_name (with length p_length)
* with the C string p_name, and return 1 iff both strings are equal.
* NOTE: p_iso_name may be a file name (with version number) or a directory
* name (without version number).
*/
int Names_Equal (char *p_iso_name, int p_length, char *p_name)
{
int pos;
if (Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
p_name[p_length] == 0)
return TRUE;
/* compare without version number: */
for (pos=p_length-1; pos>=0; pos--)
if (p_iso_name[pos] == ';')
break;
if (pos>=0)
return (Strncasecmp (p_iso_name, p_name, pos) == 0 &&
p_name[pos] == 0);
else
return FALSE;
}
/* Get a record from a directory.
* p_location is a LOGICAL BLOCK number.
*/
directory_record *Get_Directory_Record (VOLUME *p_volume,
unsigned long p_location,
unsigned long p_offset)
{
static unsigned char result[256];
int len;
int loc;
loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
if (!Read_Sector (p_volume->cd, loc)) {
iso_errno = ISOERR_SCSI_ERROR;
return NULL;
}
len = p_volume->cd->buffer[p_offset & 2047];
if (len)
memcpy (result, p_volume->cd->buffer + (p_offset & 2047), len);
else
result[0] = 0; /* mark as last record */
return (directory_record *) result;
}
/* Create a "CDROM object" for the directory which is located
* at sector p_location.
*/
CDROM_OBJ *Iso_Create_Directory_Obj (VOLUME *p_volume, unsigned long p_location)
{
directory_record *dir;
unsigned long loc;
int offset = 0;
CDROM_OBJ *obj;
unsigned long len;
if (p_location == VOL(p_volume,pvd).root.extent_loc_m)
return Iso_Open_Top_Level_Directory (p_volume);
dir = Get_Directory_Record (p_volume, p_location, 0);
if (!dir)
return NULL;
dir = Get_Directory_Record (p_volume, p_location, dir->length);
if (!dir)
return NULL;
loc = dir->extent_loc_m;
len = dir->data_length_m;
for (;;) {
if (offset >= len)
return NULL;
dir = Get_Directory_Record (p_volume, loc, offset);
if (!dir)
return NULL;
if (!dir->length) {
/* go to next logical sector: */
offset = (offset & 0xfffff800) + 2048;
continue;
}
if (dir->extent_loc_m == p_location)
break;
offset += dir->length;
}
obj = Iso_Alloc_Obj (dir->length);
if (!obj)
return NULL;
obj->directory_f = TRUE;
obj->volume = p_volume;
obj->pos = 0;
memcpy (OBJ(obj,dir), dir, dir->length);
return obj;
}
/* Open the object with name p_name in the directory p_dir.
* p_name must not contain '/' or ':' characters.
*/
CDROM_OBJ *Iso_Open_Obj_In_Directory (CDROM_OBJ *p_dir, char *p_name)
{
unsigned long loc = OBJ(p_dir,dir)->extent_loc_m;
unsigned long len = OBJ(p_dir,dir)->data_length_m;
directory_record *dir;
int offset;
CDROM_OBJ *obj;
/* skip first two entries: */
dir = Get_Directory_Record (p_dir->volume, loc, 0);
if (!dir)
return NULL;
offset = dir->length;
dir = Get_Directory_Record (p_dir->volume, loc, offset);
if (!dir)
return NULL;
offset += dir->length;
for (;;) {
if (offset >= len) {
iso_errno = ISOERR_NOT_FOUND;
return NULL;
}
dir = Get_Directory_Record (p_dir->volume, loc, offset);
if (!dir)
return NULL;
if (!dir->length) {
/* go to next logical sector: */
offset = (offset & 0xfffff800) + 2048;
continue;
}
if (p_dir->volume->protocol == PRO_ROCK) {
char buf[256];
int len;
if ((len = Get_RR_File_Name (p_dir->volume, dir, buf, sizeof (buf))) > 0 &&
Strncasecmp (buf, p_name, len) == 0 &&
p_name[len] == 0)
break;
}
if (Names_Equal (dir->file_id, dir->file_id_length, p_name))
break;
offset += dir->length;
}
obj = Iso_Alloc_Obj (dir->length);
if (!obj)
return NULL;
obj->directory_f = (dir->flags & 2);
obj->volume = p_dir->volume;
obj->pos = 0;
memcpy (OBJ(obj,dir), dir, dir->length);
return obj;
}
/* Close a "CDROM object" and deallocate all associated resources.
*/
void Iso_Close_Obj (CDROM_OBJ *p_object)
{
FreeMem (OBJ(p_object,dir), OBJ(p_object,dir)->length);
FreeMem (p_object->obj_info, sizeof (t_iso_obj_info));
FreeMem (p_object, sizeof (CDROM_OBJ));
}
/* Read bytes from a file.
*/
int Iso_Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
{
unsigned long loc;
int remain_block, remain_file, remain;
int len;
VOLUME *vol = p_file->volume;
CDROM *cd = vol->cd;
int buf_pos = 0;
int todo;
unsigned long last_loc, ext_loc;
short blockshift;
int offset;
if (p_file->pos == OBJ(p_file,dir)->data_length_m)
/* at end of file: */
return 0;
blockshift = VOL(vol,blockshift);
/*
* 'offset' is the offset of the first logical block of the file
* extent from the first logical (2048-byte-)sector.
*/
if (blockshift)
offset = (((OBJ(p_file,dir)->extent_loc_m) & ((1<<blockshift)-1))
<< (11-blockshift));
else
offset = 0;
/*
* 'ext_loc' is the first logical sector of the file extent.
* 'loc' is the first logical sector to be read.
* 'last_loc' is the last logical sector of the file extent.
*/
ext_loc = OBJ(p_file,dir)->extent_loc_m >> blockshift;
loc = ext_loc + ((p_file->pos + offset) >> 11);
last_loc = ext_loc + ((OBJ(p_file,dir)->data_length_m + offset - 1) >> 11);
todo = p_buffer_length;
offset += p_file->pos;
offset &= 2047;
remain_block = 2048 - offset;
while (todo) {
if (!Read_Contiguous_Sectors (cd, loc, last_loc)) {
iso_errno = ISOERR_SCSI_ERROR;
return -1;
}
remain_file = OBJ(p_file,dir)->data_length_m - p_file->pos;
/*
* 'todo' is the number of bytes in p_buffer which haven't been filled yet.
* 'remain' is remaining number of bytes in cd->buffer.
*/
remain = (remain_block < remain_file) ? remain_block : remain_file;
len = (todo < remain) ? todo : remain;
CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
buf_pos += len;
p_file->pos += len;
todo -= len;
if (p_file->pos >= OBJ(p_file,dir)->data_length_m)
break;
remain_block = 2048;
offset = 0;
loc++;
}
return buf_pos;
}
t_ulong Extract_Date (directory_record *p_dir_record)
{
struct ClockData ClockData;
ClockData.sec = p_dir_record->second;
ClockData.min = p_dir_record->minute;
ClockData.hour = p_dir_record->hour;
ClockData.mday = p_dir_record->day;
ClockData.wday = 0; /* is ignored by CheckDate() and Date2Amiga() */
ClockData.month = p_dir_record->month;
ClockData.year = p_dir_record->year + 1900;
if (CheckDate (&ClockData))
return Date2Amiga (&ClockData);
else
return 0;
}
/* Return information on a "CDROM object."
*/
int Iso_CDROM_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
{
int len;
if (Iso_Is_Top_Level_Object (p_obj)) {
p_info->name_length = 1;
p_info->name[0] = ':';
p_info->directory_f = TRUE;
p_info->file_length = 0;
p_info->date = Volume_Creation_Date (p_obj->volume);
} else {
if (p_obj->volume->protocol == PRO_ROCK &&
(len = Get_RR_File_Name (p_obj->volume, OBJ(p_obj,dir),
p_info->name, sizeof (p_info->name))) > 0) {
p_info->name_length = len;
} else {
p_info->name_length = OBJ(p_obj,dir)->file_id_length;
memcpy (p_info->name, OBJ(p_obj,dir)->file_id, p_info->name_length);
}
p_info->directory_f = p_obj->directory_f;
p_info->file_length = OBJ(p_obj,dir)->data_length_m;
p_info->date = Extract_Date (OBJ(p_obj,dir));
}
return 1;
}
/* Browse all entries in a directory.
*/
int Iso_Examine_Next (CDROM_OBJ *p_dir, CDROM_INFO *p_info,
unsigned long *p_offset)
{
unsigned long offset;
directory_record *rec;
int len;
if (!p_dir->directory_f) {
iso_errno = ISOERR_BAD_ARGUMENTS;
return 0;
}
if (*p_offset == 0) {
/* skip first two directory entries: */
rec = Get_Directory_Record (p_dir->volume,
OBJ(p_dir,dir)->extent_loc_m,
0);
if (!rec)
return 0;
offset = rec->length;
rec = Get_Directory_Record (p_dir->volume,
OBJ(p_dir,dir)->extent_loc_m,
offset);
if (!rec)
return 0;
*p_offset = offset + rec->length;
}
for (;;) {
if (OBJ(p_dir,dir)->data_length_m <= *p_offset)
return 0;
rec = Get_Directory_Record (p_dir->volume,
OBJ(p_dir,dir)->extent_loc_m,
*p_offset);
if (!rec)
return 0;
if (rec->length == 0)
/* go to next logical sector: */
*p_offset = (*p_offset & 0xfffff800) + 2048;
else
break;
}
*p_offset += rec->length;
if (p_dir->volume->protocol == PRO_ROCK &&
(len = Get_RR_File_Name (p_dir->volume, rec,
p_info->name, sizeof (p_info->name))) > 0) {
p_info->name_length = len;
} else {
p_info->name_length = rec->file_id_length;
memcpy (p_info->name, rec->file_id, rec->file_id_length);
}
p_info->directory_f = rec->flags & 2;
p_info->file_length = rec->data_length_m;
p_info->date = Extract_Date (rec);
p_info->suppl_info = rec;
return 1;
}
/* Clone a "CDROM object info."
*/
void *Iso_Clone_Obj_Info (void *p_info)
{
t_iso_obj_info *info = (t_iso_obj_info *) p_info;
t_iso_obj_info *new;
new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
if (!new)
return NULL;
memcpy (new, info, sizeof (t_iso_obj_info));
new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
if (!new->dir) {
FreeMem (new, sizeof (t_iso_obj_info));
return NULL;
}
memcpy (new->dir, info->dir, info->dir->length);
return new;
}
/* Find parent directory.
*/
CDROM_OBJ *Iso_Find_Parent (CDROM_OBJ *p_object)
{
directory_record *dir;
dir = Get_Directory_Record (p_object->volume,
OBJ(p_object,dir)->extent_loc_m,
0);
if (!dir)
return NULL;
dir = Get_Directory_Record (p_object->volume,
OBJ(p_object,dir)->extent_loc_m,
dir->length);
if (!dir)
return NULL;
return Iso_Create_Directory_Obj (p_object->volume, dir->extent_loc_m);
}
/* Test if p_object is the root directory.
*/
t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *p_object)
{
return p_object->directory_f &&
OBJ(p_object,dir)->extent_loc_m ==
VOL(p_object->volume,pvd).root.extent_loc_m;
}
/* Test if two objects are equal.
*/
t_bool Iso_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
{
return (OBJ(p_obj1,dir)->extent_loc_m ==
OBJ(p_obj2,dir)->extent_loc_m);
}
/*
* Convert p_num digits into an integer value:
*/
int Digs_To_Int (char *p_digits, int p_num)
{
int result = 0;
int i;
for (i=0; i<p_num; i++)
result = result * 10 + p_digits[i] - '0';
return result;
}
/*
* Return volume creation date as number of seconds since 1-Jan-1978:
*/
t_ulong Iso_Creation_Date (VOLUME *p_volume)
{
struct ClockData ClockData;
char *dt = VOL(p_volume,pvd).vol_creation;
ClockData.sec = Digs_To_Int (dt+12, 2);
ClockData.min = Digs_To_Int (dt+10, 2);
ClockData.hour = Digs_To_Int (dt+8, 2);
ClockData.mday = Digs_To_Int (dt+6, 2);
ClockData.wday = 0; /* is ignored by CheckDate() and Date2Amiga() */
ClockData.month = Digs_To_Int (dt+4, 2);
ClockData.year = Digs_To_Int (dt, 4);
if (CheckDate (&ClockData))
return Date2Amiga (&ClockData);
else
return 0;
}
t_ulong Iso_Volume_Size (VOLUME *p_volume)
{
return VOL(p_volume,pvd).space_size_m;
}
t_ulong Iso_Block_Size (VOLUME *p_volume)
{
return VOL(p_volume,pvd).block_size_m;
}
void Iso_Volume_ID (VOLUME *p_volume, char *p_buffer, int p_buf_length)
{
char *iso_name = VOL(p_volume,pvd).volume_id;
int iso_len;
int len;
for (iso_len = 32; iso_len; iso_len--) {
if (iso_name[iso_len-1] != ' ')
break;
}
len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
if (len > 0)
memcpy (p_buffer, iso_name, len);
p_buffer[len] = 0;
}
t_ulong Iso_Location (CDROM_OBJ *p_object)
{
return OBJ(p_object,dir)->extent_loc_m;
}
t_ulong Iso_File_Length (CDROM_OBJ *p_obj)
{
return OBJ(p_obj,dir)->data_length_m;
}
t_handler g_iso_handler = {
Iso_Close_Vol_Info,
Iso_Open_Top_Level_Directory,
Iso_Open_Obj_In_Directory,
Iso_Find_Parent,
Iso_Close_Obj,
Iso_Read_From_File,
Iso_CDROM_Info,
Iso_Examine_Next,
Iso_Clone_Obj_Info,
Iso_Is_Top_Level_Object,
Iso_Same_Objects,
Iso_Creation_Date,
Iso_Volume_Size,
Iso_Volume_ID,
Iso_Location,
Iso_File_Length,
Iso_Block_Size
};
t_handler g_rr_handler = {
Iso_Close_Vol_Info,
Iso_Open_Top_Level_Directory,
Iso_Open_Obj_In_Directory,
Iso_Find_Parent,
Iso_Close_Obj,
Iso_Read_From_File,
Iso_CDROM_Info,
Iso_Examine_Next,
Iso_Clone_Obj_Info,
Iso_Is_Top_Level_Object,
Iso_Same_Objects,
Iso_Creation_Date,
Iso_Volume_Size,
Iso_Volume_ID,
Iso_Location,
Iso_File_Length,
Iso_Block_Size
};